package com.android.wlw_local.otg;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.text.format.Time;
import android.util.Log;
import android.widget.Toast;

import com.android.commonlib.loop.HandlerLooper;
import com.android.wlw_local.MainActivity;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.IOException;
import java.util.Random;

import tw.com.prolific.driver.pl2303.PL2303Driver;

/**
 * Created by zhuqin on 2018/3/6.
 */

public class OTGService extends Service implements OTGInterface{

    private static final String TAG = OTGService.class.getSimpleName();
    /**USB 权限**/
    private static final String ACTION_USB_PERMISSION = "com.prolific.pl2303hxdsimpletest.USB_PERMISSION";

    private PL2303Driver mSerial;

    private PL2303Driver.BaudRate mBaudrate = PL2303Driver.BaudRate.B9600;
    private PL2303Driver.DataBits mDataBits = PL2303Driver.DataBits.D8;
    private PL2303Driver.Parity mParity = PL2303Driver.Parity.NONE;
    private PL2303Driver.StopBits mStopBits = PL2303Driver.StopBits.S1;
    private PL2303Driver.FlowControl mFlowControl = PL2303Driver.FlowControl.OFF;

    private boolean isRun = true ;

    private Thread loopThread ;


    private HandlerLooper tempHandlerLooper ;

    private HandlerLooper waterLevelHandlerLooper ;
    /**
     *
     * 绑定服务时才会调用
     * 必须要实现的方法
     * @param intent
     * @return
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 首次创建服务时，系统将调用此方法来执行一次性设置程序（在调用 onStartCommand() 或 onBind() 之前）。
     * 如果服务已在运行，则不会调用此方法。该方法只被调用一次
     */
    @Override
    public void onCreate() {
        super.onCreate();
        registerEventBus();
        initData();
        runLoop();
    }

    /**
     * 每次通过startService()方法启动Service时都会被回调。
     * @param intent
     * @param flags
     * @param startId
     * @return
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if(mSerial == null){
            initData();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * 销毁
     */
    @Override
    public void onDestroy() {
        super.onDestroy();
        isRun = false ;
        if(tempHandlerLooper!= null){
            tempHandlerLooper.onDestory();
            tempHandlerLooper = null ;
        }
        if(waterLevelHandlerLooper!= null){
            waterLevelHandlerLooper.onDestory();
            waterLevelHandlerLooper = null ;
        }
        removeEventBus();
    }


    private void initData(){
        mSerial = new PL2303Driver((UsbManager) getSystemService(Context.USB_SERVICE),this, ACTION_USB_PERMISSION);
        // check USB host function.
        if (!mSerial.PL2303USBFeatureSupported()) {
            Toast.makeText(this, "No Support USB host API", Toast.LENGTH_SHORT) .show();
            mSerial = null;
        }
        openUsbSerial();
    }



    @Override
    public void openUsbSerial() {
        if(null==mSerial)
            return;

        if (mSerial.isConnected()) {
            int baudRate= OTGConfigStore.BPS115200;
            switch (baudRate) {
                case OTGConfigStore.BPS9600:
                    mBaudrate = PL2303Driver.BaudRate.B9600;
                    break;
                case OTGConfigStore.BPS19200:
                    mBaudrate =PL2303Driver.BaudRate.B19200;
                    break;
                case OTGConfigStore.BPS115200:
                    mBaudrate =PL2303Driver.BaudRate.B115200;
                    break;
                default:
                    mBaudrate =PL2303Driver.BaudRate.B115200;
                    break;
            }
            Toast.makeText(this, "start : " , Toast.LENGTH_SHORT).show();
            // if (!mSerial.InitByBaudRate(mBaudrate)) {
            if (!mSerial.InitByBaudRate(mBaudrate,700)) {
                if(!mSerial.PL2303Device_IsHasPermission()) {
                    Toast.makeText(this, "cannot open, maybe no permission", Toast.LENGTH_SHORT).show();
                }
                if(mSerial.PL2303Device_IsHasPermission() && (!mSerial.PL2303Device_IsSupportChip())) {
                    Toast.makeText(this, "cannot open, maybe this chip has no support, please use PL2303HXD / RA / EA chip.", Toast.LENGTH_SHORT).show();
                }
                Toast.makeText(this, "initByBaudRate", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "connected : " , Toast.LENGTH_SHORT).show();
            }
        }//isConnected

    }//openUsbSerial

    @Override
    public void runLoop() {
        if( loopThread == null) {
            loopThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while (isRun) {

                        int len;
                        // byte[] rbuf = new byte[4096];
                        byte[] rbuf = new byte[20];
                        StringBuffer sbHex = new StringBuffer();

                        Log.d(TAG, "Enter readDataFromSerial");

                        msgHandler.sendEmptyMessage(111);
                        if (null == mSerial) {
                            msgHandler.sendEmptyMessage(222);
                            return;
                        }
                        if (!mSerial.isConnected()) {
                            msgHandler.sendEmptyMessage(333);
                            return;
                        }

                        len = mSerial.read(rbuf);
                        if (len < 0) {
                            msgHandler.sendEmptyMessage(444);
                            Log.d(TAG, "Fail to bulkTransfer(read data)");
                            return;
                        }

                        if (len > 0) {
                            //rbuf[len] = 0;
                            for (int j = 0; j < len; j++) {
                                //String temp=Integer.toHexString(rbuf[j]&0x000000FF);
                                //Log.i(TAG, "str_rbuf["+j+"]="+temp);
                                //int decimal = Integer.parseInt(temp, 16);
                                //Log.i(TAG, "dec["+j+"]="+decimal);
                                //sbHex.append((char)decimal);
                                //sbHex.append(temp);
                                sbHex.append((char) (rbuf[j] & 0x000000FF));
                            }
                            msgHandler.sendEmptyMessage(555);
                            Message msg = new Message();
                            Bundle bundle = new Bundle();
                            bundle.putString("value", sbHex.toString());
                            msg.setData(bundle);
                            loopHandler.sendMessage(msg);
                        }
                        msgHandler.sendEmptyMessage(666);
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });
        }
        loopThread.start();
    }

    @Override
    public void registerEventBus() {
        EventBus.getDefault().register(this);
    }

    @Override
    public void removeEventBus() {
        EventBus.getDefault().unregister(this);
    }

    @Subscribe
    public void onAcceptCommond(String commond) {
        if(!commond.startsWith("OTGService:")){
            return;
        }
        String resCommond = commond.split(":")[1];
        if(resCommond.equals("startLoopByTemp")){
            if(tempHandlerLooper!= null){
                tempHandlerLooper.onDestory();
                tempHandlerLooper = null;
            }
            tempHandlerLooper = HandlerLooper.getInstante();
            tempHandlerLooper.onStart(10 * 60 * 1000, new HandlerLooper.TaskContent() {
                @Override
                public void excuteTask() {
                    writeDataToSerial("M105\\n");
                }
            });
        }else if(resCommond.equals("startLoopByWaterLevel")){
            if(waterLevelHandlerLooper != null){
                waterLevelHandlerLooper.onDestory();
                waterLevelHandlerLooper = null ;
            }
            waterLevelHandlerLooper = HandlerLooper.getInstante();
            waterLevelHandlerLooper.onStart(10 * 60 * 1000, new HandlerLooper.TaskContent() {
                @Override
                public void excuteTask() {
                    writeDataToSerial("M505\\n");
                }
            });
        }else {
            writeDataToSerial(resCommond);
        }
    }

    @Override
    public void writeDataToSerial(String text) {
        Log.d(TAG, "Enter writeDataToSerial");

        if(null==mSerial)
            return;

        if(!mSerial.isConnected())
            return;
        int res = mSerial.write(text.getBytes(), text.length());
        if( res<0 ) {
            loopHandler.sendEmptyMessage(777);
            Log.d(TAG, "setup2: fail to controlTransfer: "+ res);
            return;
        }
        loopHandler.sendEmptyMessage(888);
    }



    //------------------------------------------------------------------------------------------------//
    //--------------------------------------LoopBack function-----------------------------------------//
    //------------------------------------------------------------------------------------------------//
    private static final int START_NOTIFIER = 0x100;
    private static final int STOP_NOTIFIER = 0x101;
    private static final int PROG_NOTIFIER_SMALL = 0x102;
    private static final int PROG_NOTIFIER_LARGE = 0x103;
    private static final int ERROR_BAUDRATE_SETUP = 0x8000;
    private static final int ERROR_WRITE_DATA = 0x8001;
    private static final int ERROR_WRITE_LEN = 0x8002;
    private static final int ERROR_READ_DATA = 0x8003;
    private static final int ERROR_READ_LEN = 0x8004;
    private static final int ERROR_COMPARE_DATA = 0x8005;

    Handler myMessageHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch(msg.what){
                case START_NOTIFIER:
//                    pbLoopBack.setProgress(0);
//                    tvLoopBack.setText("LoopBack Test start...");
//                    btWrite.setEnabled(false);
//                    btRead.setEnabled(false);
                    break;
                case STOP_NOTIFIER:
//                    pbLoopBack.setProgress(pbLoopBack.getMax());
//                    tvLoopBack.setText("LoopBack Test successfully!");
//                    btWrite.setEnabled(true);
//                    btRead.setEnabled(true);
                    break;
                case PROG_NOTIFIER_SMALL:
//                    pbLoopBack.incrementProgressBy(5);
                    break;
                case PROG_NOTIFIER_LARGE:
//                    pbLoopBack.incrementProgressBy(10);
                    break;
                case ERROR_BAUDRATE_SETUP:
//                    tvLoopBack.setText("Fail to setup:baudrate "+msg.arg1);
                    break;
                case ERROR_WRITE_DATA:
//                    tvLoopBack.setText("Fail to write:"+ msg.arg1);
                    break;
                case ERROR_WRITE_LEN:
//                    tvLoopBack.setText("Fail to write len:"+msg.arg2+";"+ msg.arg1);
                    break;
                case ERROR_READ_DATA:
//                    tvLoopBack.setText("Fail to read:"+ msg.arg1);
                    break;
                case ERROR_READ_LEN:
//                    tvLoopBack.setText("Length("+msg.arg2+") is wrong! "+ msg.arg1);
                    break;
                case ERROR_COMPARE_DATA:
//                    tvLoopBack.setText("wrong:"+
//                            String.format("rbuf=%02X,byteArray1=%02X", msg.arg1, msg.arg2));
                    break;

            }
            super.handleMessage(msg);
        }//handleMessage
    };

    private void Send_Notifier_Message(int mmsg) {
        Message m= new Message();
        m.what = mmsg;
        myMessageHandler.sendMessage(m);
        Log.d(TAG, String.format("Msg index: %04x", mmsg));
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void Send_ERROR_Message(int mmsg, int value1, int value2) {
        Message m= new Message();
        m.what = mmsg;
        m.arg1 = value1;
        m.arg2 = value2;
        myMessageHandler.sendMessage(m);
        Log.d(TAG, String.format("Msg index: %04x", mmsg));
    }



    final Handler loopHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            Bundle b = msg.getData();
            String res = b.getString("value");
            if(TextUtils.isEmpty(res)){
                Toast.makeText(OTGService.this,"res:"+res,Toast.LENGTH_LONG).show();
                return;
            }
            Toast.makeText(OTGService.this,"res:"+res,Toast.LENGTH_LONG).show();
            if(res.startsWith("O")){//水位
                //TODO
//                if(workPlanFragment != null){
//                    workPlanFragment.setwater_tv(res);
//                }
            }else if(res.startsWith("S1")){//湿度
                //TODO
//                if(workPlanFragment != null){
//                    workPlanFragment.setTemperature_tv(res);
//                }
            }else if(res.startsWith("H")){//水位
                //TODO
//                if(workPlanFragment != null){
//                    workPlanFragment.setwater_tv(res);
//                }
            }
        }
    };

    final Handler msgHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 111:
                    Toast.makeText(OTGService.this,"Enter readDataFromSerial", Toast.LENGTH_SHORT).show();
                    break;
                case 222:
                    Toast.makeText(OTGService.this,"serial null", Toast.LENGTH_SHORT).show();
                    break;
                case 333:
                    //TODO
//                    onoffline.setText("离线中...");
                    break;
                case 444:
                    Toast.makeText(OTGService.this,"len < 0 ", Toast.LENGTH_SHORT).show();
                    break;
                case 555:
                    Toast.makeText(OTGService.this,"555",Toast.LENGTH_SHORT).show();
                    break;
                case 666:
                    Toast.makeText(OTGService.this,"666",Toast.LENGTH_SHORT).show();
                    break;
                case 777:
                    Toast.makeText(OTGService.this,"777",Toast.LENGTH_SHORT).show();
                    break;
                case 888:
                    Toast.makeText(OTGService.this,"888",Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };
}
